/**
 * 
 */
package cyclopean.world;

import java.nio.IntBuffer;
import java.util.HashSet;
import java.util.Set;

import javagame.core.main.Time;

// TODO Javadoc
/**
 * 
 *
 * @author Jaco van der Westhuizen
 */
public class Zone
{
	// X is east, Y is north, Z is up

	static final int sizeX = 64;	// 256kB per Zone
	static final int sizeY = 64;
	static final int sizeZ = 64;
	static final int PER_X = sizeZ;
	static final int PER_Y = PER_X * sizeX;
	static final int BLOCKS_COUNT = sizeX * sizeY * sizeZ;

	final int offsetX;
	final int offsetY;
	final byte[] blocks = new byte[BLOCKS_COUNT];
	
	private final int[] renderData = new int[BLOCKS_COUNT];
	final IntBuffer dataBuffer = IntBuffer.wrap(renderData);

	private boolean changed;
	final Set<ZoneListener> listeners = new HashSet<ZoneListener>();

	Zone(int offsetX, int offsetY)
	{
		this.offsetX = offsetX;
		this.offsetY = offsetY;
		
		for (int y = 0; y < sizeY; y++)
		{
			for (int x = 0; x < sizeX; x++)
			{
				int i = PER_X * x + PER_Y * y;
				
				for (int z = 0; z < sizeZ; z++)
				{
					blocks[i] = (z < 32) ? BlockType.DIRT.id : BlockType.AIR.id;
					
					i++;
				}
			}
		}
	}

	int getBlockId(int x, int y, int z)
	{
		return z + (PER_X * x) + (PER_Y * y);
	}

	boolean setBlockType(int id, byte type)
	{
		blocks[id] = type;
		changed = true;

		return true;
	}

    public void update(Time time, UpdateLevel level)
    {
    	changed = false;
    	
    	if (level.compareTo(UpdateLevel.STATIC) <= 0)
    	{
    		// TODO Player-triggered events
    	}

    	if (level.compareTo(UpdateLevel.DISTANT) <= 0)
    	{
    		// TODO Weather
    	}

    	if (level.compareTo(UpdateLevel.STATIC) <= 0)
    	{
    		// TODO AI
    		// TODO Physics
    	}
    	
    	if (changed)
    	{
    		for (int i = 0; i < BLOCKS_COUNT; i++)
    		{
    			int d = blocks[i];
    			d |= (BlockType.isTrans[d] ? 0 : 0x01010101);//256 : 0);
    			d=0x01010101;
    			renderData[i] = d;
    		}

    		for (ZoneListener l : listeners)
    		{
    			l.onChange(this);
    		}
    	}
    }
    
    public static interface ZoneListener
    {
    	public void onChange(Zone zone);
    }
    
    static enum UpdateLevel
    {
    	LIVE,
    	DISTANT,
    	STATIC;
    }
}
